package cn.ac.aircas.framework.aspectj;

import cn.ac.aircas.common.annotation.Cache;
import cn.ac.aircas.common.constant.Constants;
import cn.ac.aircas.common.constant.HttpStatus;
import cn.ac.aircas.common.core.domain.R;
import cn.ac.aircas.common.core.redis.RedisCache;
import cn.ac.aircas.common.exception.JXException;
import cn.ac.aircas.common.utils.StringUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static cn.ac.aircas.common.constant.CacheConstants.DEFAULT_EXPIRE;

@Aspect
@Component
public class CacheAspect {

    @Value("${defected.cacheStatus}")
    String status;

    @Autowired
    private RedisCache redisCache;

//    @Autowired
//    CanalClient canal;

    @Around("@annotation(cn.ac.aircas.common.annotation.Cache)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 从切面中获取方法名
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        Cache cache = method.getAnnotation(Cache.class);
        //获取包名
        String targetName = point.getTarget().getClass().getName();
        // 获取参数名
        String methodName = method.getName();
        // 不支持参数包含HttpServletRequest等 如需要建议用@Autowired注入
        String params = point.getArgs() == null ? "" : JSON.toJSONString(point.getArgs());

        // 转换成md5
        String md5 = DigestUtils.md5Hex(targetName + methodName + params);


        if (cache != null && Objects.equals(cache.type(), Constants.PUT) && status.equals("1")) {
            R result = R.fail();
            String prefix = cache.prefix();
            md5 = prefix + ":" + md5;
            try {
//                canal.afterPropertiesSet();
//                if (CanalClient.bool) {
//                    redisService.deleteObject(md5);
//                }
                // 从redis获取缓存
                Object object = redisCache.getCacheObject(md5);
                String jsonString = object != null ? JSONObject.toJSONString(object) : null;
                if (jsonString == null || StringUtils.isBlank(jsonString)) {
                    // 读不到缓存正常执行方法
                    result = (R) point.proceed();
                    // 执行完毕后结果写入Redis缓存 只缓存正确数据
                    if (result.getCode() == HttpStatus.SUCCESS) {
                        // Cache.time() 默认值是0 如等于0 使用统一缓存时间 如不等于0 说明需要自定义，用Cache.time()
                        int time = cache.time() != 0 ? cache.time() : DEFAULT_EXPIRE;
                        redisCache.setCacheObject(md5, result.getData(), time, TimeUnit.MINUTES);
                    }
                } else {
                    // 读取到缓存直接返回，不执行方法
                    if (jsonString.startsWith("[")) {
                        result =  R.ok(JSONArray.parseArray(jsonString));
                    } else {
                        result = R.ok(JSONObject.parseObject(jsonString));
                    }

                }
            } catch (JXException e) {
                result.setCode(Integer.parseInt(e.getCode()));
                result.setMsg(e.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        } else if (cache != null && cache.type().equals(Constants.UPDATE)) {
            String prefix = cache.prefix();
            md5 = prefix + ":" + md5;
            redisCache.deleteObject(md5);
            return R.ok();
        } else {
            return (R) point.proceed();
        }
    }
}
